<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>数据代理</title>
	</head>
	<body>
		<div id="app">
			<p>{{num}}</p>
			<p>{{person.name}}</p>
			<p v-text="person.name"></p>
			<button v-on:click="handleClick">按钮</button>
		</div>

		<script src="./js/observer.js"></script>
		<script src="./js/watcher.js"></script>
		<script src="./js/compile.js"></script>
		<!-- 引入js文件，全局就会出现一个构造函数：MVVM -->
		<script src="./js/mvvm.js"></script>
		<script>
			/*
        1. 数据代理：将data中的数据代理到this，将来可以通过this直接访问data数据
            遍历data中所有数据，对每一个数据进行数据代理
            通过Object.defineProperty方法，给this添加data中的属性，属性值定义get/set
            当你通过this读取数据时。触发数据代理设置的get，实际读取原data数据的值
            当你通过this设置数据时。触发数据代理设置的set，实际设置原data数据的值

				2. 数据劫持：对原data数据进行重新定义，定义成响应式
					遍历原data中所有数据，将每个属性进行重新定义，定义成响应式
					每个属性都会产生一个dep对象，通过闭包的方式保存在属性的get/set中
					当你读取原data数据属性时，会建立起响应式联系并返回属性值
					当你设置原data数据属性时，更新属性值并触发用户界面的更新（从而达到响应式）

					问题1：响应式联系 dep.depend() 方法做了什么事？
						dep保存watcher  watcher保存dep
					问题2：触发用户界面的更新 dep.notify() 方法做了什么事？
						通知dep保存的所有watcher，调用cb方法去更新用户界面，从而达到响应式

					结论：
						1. 插值语法和除了事件指令以外的其他指令语法，都会new Watcher
						2. 所有响应式数据（data数据），都会new Dep

				3. 模板解析：解析模板页面中的模板语法（插值语法和指令语法）
					- **将元素节点添加到文档碎片节点中**
						- 遍历取出el的第一个子节点，添加文档碎片中
						- 一直循环，直到el所有子节点全部添加好，返回文档碎片节点
					- **解析文档碎片节点中所有子节点的模板语法**
						- 遍历所有子节点，判断这个节点是元素节点还是文本节点
							- 如果是元素节点，就要解析指令语法
								- 提取所有指令属性进行遍历，判断是普通指令还是事件指令
									- 普通指令会找相应的更新DOM的方法更新节点内容(new Watcher)
									- 事件指令就会绑定事件
									- 所有指令属性解析完后会被移除，所以页面就看不到指令属性了
							- 如果是文本节点并且有插值语法，就要解析插值语法
								- 和v-text解析类似，更新元素的textContent，值为表达式的值(new Watcher)
							- 如果当前节点还有子节点，需要递归编译所有子节点
					- **将解析后的文档碎片节点添加到el中生效**

				4. 响应式
					当前三步做完后，所有模板语法（除了事件指令）都会new Watcher
					new Watcher调用很多方法，其中会读取表达式的值，此时触发数据代理设置get，
					里面读取原data数据，又触发数据劫持设置get，此时就会调用dep.depend方法建立响应式联系
					响应式联系就会在
						dep中保存watcher（为了将来能通过dep找到watcher，watcher有更新用户界面的方法，从而更新用户界面）
						watcher中保存dep（为了防止重复保存）

					将来当你更新数据值时，触发数据代理设置set,里面设置原data数据，又触发数据劫持设置set，
					更新属性的值，同时调用dep.notify方法，通知dep保存所有watcher，调用cb方法来更新用户界面，从而达到响应式
    
				5. v-model的原理
					v-model给元素绑定value属性和input事件
						绑定value属性 - modelUpdater方法更新node.value
						input事件 - 给node绑定input事件，在回调函数中收集用户输入的数据更新表达式的值 
							- 此时就会触发响应式更新
		*/
			debugger; // 断点

			console.log("hello mvvm");

			new MVVM({
				// el: "#app",
				el: document.getElementById("app"),
				data: {
					num: 0,
					person: {
						name: "jack",
					},
				},
				methods: {
					handleClick() {
						debugger;
						this.num++;
					},
				},
			});
		</script>
	</body>
</html>
